#include <sdk.h>
#include <scripting/bindings/sc_base_types.h>
#include "wizpage.h"
#include "infopanel.h"
#include "projectpathpanel.h"
#include "compilerpanel.h"
#include "buildtargetpanel.h"
#include "filepathpanel.h"
#include "genericselectpath.h"
#include "genericsinglechoicelist.h"

namespace Wizard {
  void FillCompilerControl( wxItemContainer *control, const wxString& compilerID, const wxString& validCompilerIDs ) {
    const wxArrayString &valids = GetArrayFromString( validCompilerIDs, _T( ";" ), true );
    wxString def = compilerID;
    if( def.IsEmpty() ) {
      def = CompilerFactory::GetDefaultCompilerID();
    }
    int id = 0;
    control->Clear();
    for( size_t i = 0; i < CompilerFactory::GetCompilersCount(); ++i ) {
      Compiler* compiler = CompilerFactory::GetCompiler( i );
      if( compiler ) {
        for( size_t n = 0; n < valids.GetCount(); ++n ) {
          if( CompilerFactory::CompilerInheritsFrom( compiler, valids[n] ) ) {
            control->Append( compiler->GetName() );
            if( compiler->GetID().IsSameAs( def ) )
            { id = control->GetCount() < 1 ? 0 : ( control->GetCount() - 1 ); }
            break;
          }
        }
      }
    }
    control->SetSelection( id );
  }

}

using namespace Wizard;

wxString AppendPathSepIfNeeded( const wxString& path ) {
  if( path.IsEmpty() || path.Last() == _T( '/' ) || path.Last() == _T( '\\' ) ) {
    return path;
  }
  return path + wxFILE_SEP_PATH;
}

PagesByName WizPageBase::s_PagesByName;

BEGIN_EVENT_TABLE( WizPageBase, wxWizardPageSimple )
  EVT_WIZARD_PAGE_CHANGING( -1, WizPageBase::OnPageChanging )
  EVT_WIZARD_PAGE_CHANGED( -1, WizPageBase::OnPageChanged )
END_EVENT_TABLE()

WizPageBase::WizPageBase( const wxString& pageName, wxWizard* parent, const wxBitmap& bitmap )
  : wxWizardPageSimple( parent, 0, 0, bitmap ),
    m_PageName( pageName ) {
  if( s_PagesByName[m_PageName] ) {
    m_Throw( _T( "Page ID in use:" ) + pageName );
  }
  s_PagesByName[m_PageName] = this;
  m_SkipPage = Manager::Get()->GetConfigManager( _T( "scripts" ) )->ReadBool( _T( "/generic_wizard/" ) + m_PageName + _T( "/skip" ), false );
}

WizPageBase::~WizPageBase() {
  s_PagesByName[m_PageName] = 0;
}

wxWizardPage* WizPageBase::GetPrev() const {
  try {
    wxString sig = _T( "OnGetPrevPage_" ) + m_PageName;
    SqPlus::SquirrelFunction<wxString&> cb( cbU2C( sig ) );
    if( cb.func.IsNull() ) {
      return wxWizardPageSimple::GetPrev();
    }
    wxString prev = cb();
    if( prev.IsEmpty() ) {
      return 0;
    }
    return s_PagesByName[prev];
  } catch( SquirrelError& e ) {
    Manager::Get()->GetScriptingManager()->DisplayErrors( &e );
  }
  return wxWizardPageSimple::GetPrev();
}

wxWizardPage* WizPageBase::GetNext() const {
  try {
    wxString sig = _T( "OnGetNextPage_" ) + m_PageName;
    SqPlus::SquirrelFunction<wxString&> cb( cbU2C( sig ) );
    if( cb.func.IsNull() ) {
      return wxWizardPageSimple::GetNext();
    }
    wxString next = cb();
    if( next.IsEmpty() ) {
      return 0;
    }
    return s_PagesByName[next];
  } catch( SquirrelError& e ) {
    Manager::Get()->GetScriptingManager()->DisplayErrors( &e );
  }
  return wxWizardPageSimple::GetNext();
}

void WizPageBase::OnPageChanging( wxWizardEvent& event ) {
  Manager::Get()->GetConfigManager( _T( "scripts" ) )->Write( _T( "/generic_wizard/" ) + m_PageName + _T( "/skip" ), ( bool )m_SkipPage );
  try {
    wxString sig = _T( "OnLeave_" ) + m_PageName;
    SqPlus::SquirrelFunction<bool> cb( cbU2C( sig ) );
    if( cb.func.IsNull() ) {
      return;
    }
    bool allow = cb( event.GetDirection() != 0 );
    if( !allow ) {
      event.Veto();
    }
  } catch( SquirrelError& e ) {
    Manager::Get()->GetScriptingManager()->DisplayErrors( &e );
  }
}

void WizPageBase::OnPageChanged( wxWizardEvent& event ) {
  try {
    wxString sig = _T( "OnEnter_" ) + m_PageName;
    SqPlus::SquirrelFunction<void> cb( cbU2C( sig ) );
    if( cb.func.IsNull() ) {
      return;
    }
    cb( event.GetDirection() != 0 );
  } catch( SquirrelError& e ) {
    Manager::Get()->GetScriptingManager()->DisplayErrors( &e );
  }
}

BEGIN_EVENT_TABLE( WizPage, WizPageBase )
  EVT_CHOICE( -1, WizPage::OnButton )
  EVT_COMBOBOX( -1, WizPage::OnButton )
  EVT_CHECKBOX( -1, WizPage::OnButton )
  EVT_LISTBOX( -1, WizPage::OnButton )
  EVT_RADIOBOX( -1, WizPage::OnButton )
  EVT_BUTTON( -1, WizPage::OnButton )
END_EVENT_TABLE()

WizPage::WizPage( const wxString& panelName, wxWizard* parent, const wxBitmap& bitmap )
  : WizPageBase( panelName, parent, bitmap ) {
  wxXmlResource::Get()->LoadPanel( this, panelName );
}

WizPage::~WizPage() {
}

void WizPage::OnButton( wxCommandEvent& event ) {
  wxWindow* win = FindWindowById( event.GetId(), this );
  if( !win ) {
    Manager::Get()->GetLogManager()->LogError( F( _T( "找不到ID为 %d 的窗口" ), event.GetId() ) );
    return;
  }
  try {
    wxString sig = _T( "OnClick_" ) + win->GetName();
    SqPlus::SquirrelFunction<void> cb( cbU2C( sig ) );
    if( cb.func.IsNull() ) {
      return;
    }
    cb();
  } catch( SquirrelError& e ) {
    Manager::Get()->GetScriptingManager()->DisplayErrors( &e );
  }
}

WizInfoPanel::WizInfoPanel( const wxString& pageId, const wxString& intro_msg, wxWizard* parent, const wxBitmap& bitmap )
  : WizPageBase( pageId, parent, bitmap ) {
  m_InfoPanel = new InfoPanel( this );
  m_InfoPanel->SetIntroText( intro_msg );
}

WizInfoPanel::~WizInfoPanel() {
}

void WizInfoPanel::OnPageChanging( wxWizardEvent& event ) {
  if( !GetSkipPage() && event.GetDirection() != 0 ) {
    SetSkipPage( m_InfoPanel->chkSkip->GetValue() );
  }
  WizPageBase::OnPageChanging( event );
}

WizFilePathPanel::WizFilePathPanel( bool showHeaderGuard, wxWizard* parent, const wxBitmap& bitmap )
  : WizPageBase( _T( "FilePathPage" ), parent, bitmap ),
    m_AddToProject( false ) {
  ConfigManager* cfg = Manager::Get()->GetConfigManager( _T( "scripts" ) );
  m_pFilePathPanel = new FilePathPanel( this );
  m_pFilePathPanel->ShowHeaderGuard( showHeaderGuard );
  m_pFilePathPanel->SetAddToProject( cfg->ReadBool( _T( "/generic_wizard/add_file_to_project" ), true ) );
}

WizFilePathPanel::~WizFilePathPanel() {
}

int WizFilePathPanel::GetTargetIndex() const {
  if( m_pFilePathPanel ) {
    return m_pFilePathPanel->GetTargetIndex();
  }
  return -1;
}

void WizFilePathPanel::SetFilePathSelectionFilter( const wxString& filter ) {
  m_pFilePathPanel->SetFilePathSelectionFilter( filter );
}

void WizFilePathPanel::OnPageChanging( wxWizardEvent& event ) {
  if( event.GetDirection() != 0 ) {
    m_Filename = m_pFilePathPanel->GetFilename();
    m_HeaderGuard = m_pFilePathPanel->GetHeaderGuard();
    m_AddToProject = m_pFilePathPanel->GetAddToProject();
    if( m_Filename.IsEmpty() || !wxDirExists( wxPathOnly( m_Filename ) ) ) {
      InfoWindow::Tip( _T( "文件无完整路径" ), _T( "错误" ), 3500 );
      event.Veto();
      return;
    }
    ConfigManager* cfg = Manager::Get()->GetConfigManager( _T( "scripts" ) );
    cfg->Write( _T( "/generic_wizard/add_file_to_project" ), ( bool )m_pFilePathPanel->GetAddToProject() );
  }
  WizPageBase::OnPageChanging( event );
}

BEGIN_EVENT_TABLE( WizProjectPathPanel, WizPageBase )
  EVT_BUTTON( -1, WizProjectPathPanel::OnButton )
END_EVENT_TABLE()

WizProjectPathPanel::WizProjectPathPanel( wxWizard* parent, const wxBitmap& bitmap )
  : WizPageBase( _T( "ProjectPathPage" ), parent, bitmap ) {
  m_pProjectPathPanel = new ProjectPathPanel( this );
}

WizProjectPathPanel::~WizProjectPathPanel() {
}

wxString WizProjectPathPanel::GetPath() const {
  return AppendPathSepIfNeeded( m_pProjectPathPanel->GetPath() );
}

wxString WizProjectPathPanel::GetName() const {
  return m_pProjectPathPanel->GetName();
}

wxString WizProjectPathPanel::GetFullFileName() const {
  return m_pProjectPathPanel->GetFullFileName();
}

wxString WizProjectPathPanel::GetTitle() const {
  return m_pProjectPathPanel->GetTitle();
}

void WizProjectPathPanel::OnButton( M_Code_unused wxCommandEvent& event ) {
  wxString dir = m_pProjectPathPanel->GetPath();
  dir = ChooseDirectory( 0, _T( "选择要在其创建项目的文件夹" ), dir, wxEmptyString, false, true );
  if( !dir.IsEmpty() && wxDirExists( dir ) ) {
    m_pProjectPathPanel->SetPath( dir );
  }
}

void WizProjectPathPanel::OnPageChanging( wxWizardEvent& event ) {
  if( event.GetDirection() != 0 ) {
    wxString dir = m_pProjectPathPanel->GetPath();
    wxString name = m_pProjectPathPanel->GetName();
    wxString fullname = m_pProjectPathPanel->GetFullFileName();
    wxString title = m_pProjectPathPanel->GetTitle();
    if( title.IsEmpty() ) {
      InfoWindow::Tip( _T( "项目无标题" ), _T( "错误" ), 3500 );
      event.Veto();
      return;
    }
    if( name.IsEmpty() ) {
      InfoWindow::Tip( _T( "项目无名称" ), _T( "错误" ), 3500 );
      event.Veto();
      return;
    }
    if( wxFileExists( fullname ) ) {
      if( msging( _T( "项目文件夹中已存在同名项目.\n"
                      "是否确实要使用此目录（文件可能被覆盖）?" ),
                  _T( "确认" ),
                  wxICON_QUESTION | wxYES_NO, GetParent() ) != wxID_YES ) {
        event.Veto();
        return;
      }
    }
    Manager::Get()->GetProjectManager()->SetDefaultPath( dir );
  }
  WizPageBase::OnPageChanging( event );
}

void WizProjectPathPanel::OnPageChanged( wxWizardEvent& event ) {
  if( event.GetDirection() != 0 ) {
    wxString dir = Manager::Get()->GetProjectManager()->GetDefaultPath();
    m_pProjectPathPanel->SetPath( dir );
  }
  WizPageBase::OnPageChanged( event );
}

BEGIN_EVENT_TABLE( WizGenericSelectPathPanel, WizPageBase )
  EVT_BUTTON( -1, WizGenericSelectPathPanel::OnButton )
END_EVENT_TABLE()

WizGenericSelectPathPanel::WizGenericSelectPathPanel( const wxString& pageId, const wxString& descr, const wxString& label, const wxString& defValue,
    wxWizard* parent, const wxBitmap& bitmap )
  : WizPageBase( pageId, parent, bitmap ) {
  wxString savedValue = Manager::Get()->GetConfigManager( _T( "project_wizard" ) )->Read( _T( "/generic_paths/" ) + pageId );
  if( savedValue.IsEmpty() ) {
    savedValue = defValue;
  }
  m_pGenericSelectPath = new GenericSelectPath( this );
  m_pGenericSelectPath->txtFolder->SetValue( savedValue );
  m_pGenericSelectPath->SetDescription( descr );
  m_pGenericSelectPath->lblLabel->SetLabel( label );
}

WizGenericSelectPathPanel::~WizGenericSelectPathPanel() {
}

void WizGenericSelectPathPanel::OnButton( M_Code_unused wxCommandEvent& event ) {
  wxString dir = Manager::Get()->GetMacrosManager()->ReplaceMacros( m_pGenericSelectPath->txtFolder->GetValue() );
  dir = ChooseDirectory( this, _T( "选择位置" ), dir, wxEmptyString, false, true );
  if( !dir.IsEmpty() && wxDirExists( dir ) ) {
    m_pGenericSelectPath->txtFolder->SetValue( dir );
  }
}

void WizGenericSelectPathPanel::OnPageChanging( wxWizardEvent& event ) {
  if( event.GetDirection() != 0 ) {
    wxString dir = Manager::Get()->GetMacrosManager()->ReplaceMacros( m_pGenericSelectPath->txtFolder->GetValue() );
    if( !wxDirExists( dir ) ) {
      msging( _T( "无效位置..." ), _T( "错误" ), wxICON_ERROR, GetParent() );
      event.Veto();
      return;
    }
  }
  WizPageBase::OnPageChanging( event );
  if( event.GetDirection() != 0 && event.IsAllowed() ) {
    Manager::Get()->GetConfigManager( _T( "project_wizard" ) )->Write( _T( "/generic_paths/" ) + GetPageName(), m_pGenericSelectPath->txtFolder->GetValue() );
  }
}

WizCompilerPanel::WizCompilerPanel( const wxString& compilerID, const wxString& validCompilerIDs, wxWizard* parent, const wxBitmap& bitmap,
                                    bool allowCompilerChange, bool allowConfigChange )
  : WizPageBase( _T( "CompilerPage" ), parent, bitmap ),
    m_AllowConfigChange( allowConfigChange ) {
  m_pCompilerPanel = new CompilerPanel( this, GetParent() );
  wxComboBox* cmb = m_pCompilerPanel->GetCompilerCombo();
  FillCompilerControl( cmb, compilerID, validCompilerIDs );
  cmb->Enable( allowCompilerChange );
  m_pCompilerPanel->EnableConfigurationTargets( m_AllowConfigChange );
  ConfigManager* cfg = Manager::Get()->GetConfigManager( _T( "scripts" ) );
  m_pCompilerPanel->SetWantDebug( cfg->ReadBool( _T( "/generic_wizard/want_debug" ), true ) );
  m_pCompilerPanel->SetDebugName( cfg->Read( _T( "/generic_wizard/debug_name" ), _T( "Debug" ) ) );
  m_pCompilerPanel->SetDebugOutputDir( cfg->Read( _T( "/generic_wizard/debug_output" ), _T( "bin/Debug" ) ) );
  m_pCompilerPanel->SetDebugObjectOutputDir( cfg->Read( _T( "/generic_wizard/debug_objects_output" ), _T( "/tmp/obj/Debug" ) ) );
  m_pCompilerPanel->SetWantRelease( cfg->ReadBool( _T( "/generic_wizard/want_release" ), true ) );
  m_pCompilerPanel->SetReleaseName( cfg->Read( _T( "/generic_wizard/release_name" ), _T( "Release" ) ) );
  m_pCompilerPanel->SetReleaseOutputDir( cfg->Read( _T( "/generic_wizard/release_output" ), _T( "bin/Release" ) ) );
  m_pCompilerPanel->SetReleaseObjectOutputDir( cfg->Read( _T( "/generic_wizard/release_objects_output" ), _T( "/tmp/obj/Release" ) ) );
}

WizCompilerPanel::~WizCompilerPanel() {
}

wxString WizCompilerPanel::GetCompilerID() const {
  Compiler* compiler = CompilerFactory::GetCompilerByName( m_pCompilerPanel->GetCompilerCombo()->GetStringSelection() );
  if( compiler ) {
    return compiler->GetID();
  }
  return wxEmptyString;
}

bool WizCompilerPanel::GetWantDebug() const {
  return m_pCompilerPanel->GetWantDebug();
}

wxString WizCompilerPanel::GetDebugName() const {
  return m_pCompilerPanel->GetDebugName();
}

wxString WizCompilerPanel::GetDebugOutputDir() const {
  return AppendPathSepIfNeeded( m_pCompilerPanel->GetDebugOutputDir() );
}

wxString WizCompilerPanel::GetDebugObjectOutputDir() const {
  return AppendPathSepIfNeeded( m_pCompilerPanel->GetDebugObjectOutputDir() );
}

bool WizCompilerPanel::GetWantRelease() const {
  return m_pCompilerPanel->GetWantRelease();
}

wxString WizCompilerPanel::GetReleaseName() const {
  return m_pCompilerPanel->GetReleaseName();
}

wxString WizCompilerPanel::GetReleaseOutputDir() const {
  return AppendPathSepIfNeeded( m_pCompilerPanel->GetReleaseOutputDir() );
}

wxString WizCompilerPanel::GetReleaseObjectOutputDir() const {
  return AppendPathSepIfNeeded( m_pCompilerPanel->GetReleaseObjectOutputDir() );
}

void WizCompilerPanel::OnPageChanging( wxWizardEvent& event ) {
  if( event.GetDirection() != 0 ) {
    if( GetCompilerID().IsEmpty() ) {
      msging( _T( "必须为项目选择编译器..." ), _T( "错误" ), wxICON_ERROR, GetParent() );
      event.Veto();
      return;
    }
    if( m_AllowConfigChange && !GetWantDebug() && !GetWantRelease() ) {
      msging( _T( "必须至少选择一个配置..." ), _T( "错误" ), wxICON_ERROR, GetParent() );
      event.Veto();
      return;
    }
    if( m_AllowConfigChange ) {
      ConfigManager* cfg = Manager::Get()->GetConfigManager( _T( "scripts" ) );
      cfg->Write( _T( "/generic_wizard/want_debug" ), ( bool )GetWantDebug() );
      cfg->Write( _T( "/generic_wizard/debug_name" ), GetDebugName() );
      cfg->Write( _T( "/generic_wizard/debug_output" ), GetDebugOutputDir() );
      cfg->Write( _T( "/generic_wizard/debug_objects_output" ), GetDebugObjectOutputDir() );
      cfg->Write( _T( "/generic_wizard/want_release" ), ( bool )GetWantRelease() );
      cfg->Write( _T( "/generic_wizard/release_name" ), GetReleaseName() );
      cfg->Write( _T( "/generic_wizard/release_output" ), GetReleaseOutputDir() );
      cfg->Write( _T( "/generic_wizard/release_objects_output" ), GetReleaseObjectOutputDir() );
    }
  }
  WizPageBase::OnPageChanging( event );
}



WizBuildTargetPanel::WizBuildTargetPanel( const wxString& targetName, bool isDebug,
    wxWizard* parent, const wxBitmap& bitmap,
    bool showCompiler,
    const wxString& compilerID, const wxString& validCompilerIDs,
    bool allowCompilerChange )
  : WizPageBase( _T( "BuildTargetPage" ), parent, bitmap ) {
  m_pBuildTargetPanel = new BuildTargetPanel( this );
  m_pBuildTargetPanel->SetTargetName( targetName );
  m_pBuildTargetPanel->SetEnableDebug( isDebug );
  m_pBuildTargetPanel->ShowCompiler( showCompiler );
  if( showCompiler ) {
    wxComboBox* cmb = m_pBuildTargetPanel->GetCompilerCombo();
    FillCompilerControl( cmb, compilerID, validCompilerIDs );
    cmb->Enable( allowCompilerChange );
  }
}

WizBuildTargetPanel::~WizBuildTargetPanel() {
}

wxString WizBuildTargetPanel::GetCompilerID() const {
  if( !m_pBuildTargetPanel->GetCompilerCombo()->IsShown() ) {
    return wxEmptyString;
  }
  Compiler* compiler = CompilerFactory::GetCompilerByName( m_pBuildTargetPanel->GetCompilerCombo()->GetStringSelection() );
  if( compiler ) {
    return compiler->GetID();
  }
  return wxEmptyString;
}

bool WizBuildTargetPanel::GetEnableDebug() const {
  return m_pBuildTargetPanel->GetEnableDebug();
}

wxString WizBuildTargetPanel::GetTargetName() const {
  return m_pBuildTargetPanel->GetTargetName();
}

wxString WizBuildTargetPanel::GetTargetOutputDir() const {
  return AppendPathSepIfNeeded( m_pBuildTargetPanel->GetOutputDir() );
}

wxString WizBuildTargetPanel::GetTargetObjectOutputDir() const {
  return AppendPathSepIfNeeded( m_pBuildTargetPanel->GetObjectOutputDir() );
}

void WizBuildTargetPanel::OnPageChanging( wxWizardEvent& event ) {
  if( event.GetDirection() != 0 ) {
    if( m_pBuildTargetPanel->GetCompilerCombo()->IsShown() && GetCompilerID().IsEmpty() ) {
      msging( _T( "必须为生成目标选择编译器..." ), _T( "错误" ), wxICON_ERROR, GetParent() );
      event.Veto();
      return;
    }
    M_Code_Project* theproject = Manager::Get()->GetProjectManager()->GetActiveProject();
    if( theproject->GetBuildTarget( m_pBuildTargetPanel->GetTargetName() ) ) {
      msging( _T( "活动项目中已存在同名的生成目标..." ), _T( "错误" ), wxICON_ERROR, GetParent() );
      event.Veto();
      return;
    }
  }
  WizPageBase::OnPageChanging( event );
}

WizGenericSingleChoiceList::WizGenericSingleChoiceList( const wxString& pageId, const wxString& descr, const wxArrayString& choices, int defChoice, wxWizard* parent, const wxBitmap& bitmap )
  : WizPageBase( pageId, parent, bitmap ) {
  int savedValue = Manager::Get()->GetConfigManager( _T( "project_wizard" ) )->ReadInt( _T( "/generic_single_choices/" ) + pageId, -1 );
  if( savedValue == -1 ) {
    savedValue = defChoice;
  }
  m_pGenericSingleChoiceList = new GenericSingleChoiceList( this );
  m_pGenericSingleChoiceList->SetDescription( descr );
  m_pGenericSingleChoiceList->SetChoices( choices, savedValue );
}

WizGenericSingleChoiceList::~WizGenericSingleChoiceList() {
}

int WizGenericSingleChoiceList::GetChoice() const {
  return m_pGenericSingleChoiceList->GetChoice();
}

void WizGenericSingleChoiceList::SetChoice( int choice ) {
  m_pGenericSingleChoiceList->SetChoice( choice );
}

void WizGenericSingleChoiceList::OnPageChanging( wxWizardEvent& event ) {
  WizPageBase::OnPageChanging( event );
  if( event.GetDirection() != 0 && event.IsAllowed() ) {
    Manager::Get()->GetConfigManager( _T( "project_wizard" ) )->Write( _T( "/generic_single_choices/" ) + GetPageName(), ( int )m_pGenericSingleChoiceList->GetChoice() );
  }
}
